﻿////////////////////////////////////////////////////////////////////////////////////////
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING THIS SOFTWARE
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install, copy or use the software.
//
// Copyright (C) 2013, AerVision Technologies Pty Ltd, all rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of AerVision Technologies, may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors to demonstrate 
// www.AerCloud.net Framework as a Service API (FaaS), "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the copyright holder or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
////////////////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.Threading;
using System.Windows.Threading;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.ServiceModel;
using System.Net;
using App_AerCloudDemo.Utils;
using System.Diagnostics;

namespace App_AerCloudDemo
{
    public partial class MainWindow : Window
    {
        private static bool customXertificateValidation(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
        {
            var cert = (System.Security.Cryptography.X509Certificates.X509Certificate2)certificate;
            if (sslPolicyErrors.HasFlag(System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors))
                MessageLogger.Default.WriteLineWithTime("*** WARNING: The SSL certificate provided by the server is not trusted.");
            return true;
        }

        public MainWindow()
        {
            InitializeComponent();
            
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
            
            ServicePointManager.ServerCertificateValidationCallback += customXertificateValidation;

            MessageLogger.Default.MessageLogged += new MessageLogger.MessageLogEventHandler(MessageLogCallback);
            txtAccessKey.Text = Settings.Default.AccessKey;

            AerCloudNet_Interface.InitConnection(this);

            var files = Directory.GetFiles(Directory.GetCurrentDirectory() + @"\Resources\DB\");
            foreach (var fileName in files)
            {
                var s = System.IO.Path.GetFileName(fileName);

                var item = new ListBoxItem();
                item.Content = s;
                lbxFileList.Items.Add(item);
            }

            files = Directory.GetFiles(Directory.GetCurrentDirectory() + @"\Resources\Query\");
            foreach (var fileName in files)
            {
                var s = System.IO.Path.GetFileName(fileName);

                var item = new ListBoxItem();
                item.Content = s;
                lbxQueryFileList.Items.Add(item);
            }

            ImageCache.loadingImage = new BitmapImage(new Uri(Directory.GetCurrentDirectory() + @"\Resources\Loading.png"));
        }

        void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Exception ex = e.ExceptionObject as Exception;
            MessageBox.Show(ex.Message, "Uncaught Exception", MessageBoxButton.OK, MessageBoxImage.Error);
            MessageLogger.Default.WriteLineWithTime("Error: " + e.ToString());
        }

        private void MessageLogCallback(string message)
        {
            if (Dispatcher.HasShutdownStarted)
                return;

            Dispatcher.Invoke(new Action<string>(delegate(string p_message)
            {
                string s = this.txtStatus.Text + p_message + "\n";
                if (s.Length > 50000)
                {
                    int i = s.IndexOf("\n", s.Length - 50000);
                    if (i > 0)
                        s = s.Substring(i + 1);
                }
                this.txtStatus.Text = s;
                this.txtStatus.CaretIndex = this.txtStatus.Text.Length;
                this.txtStatus.ScrollToEnd();

                ImageUtils.ForceUIToUpdate();
            }), message);
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Settings.Default.Save();
        }

        private void txtAccessKey_TextChanged(object sender, TextChangedEventArgs e)
        {
            Settings.Default.AccessKey = txtAccessKey.Text.Trim();
            NameCache.Clear();
            UpdateControls();
        }

        public void UpdateControls()
        {
            Dispatcher.Invoke(new Action(() =>
                {
                    var isConnected = AerCloudNet_Interface.IsConnected();

                    lblAccessKey.IsEnabled = !isConnected;

                    lbxFileList.IsEnabled = (lbxFileList.Items.Count > 0); 
                    btnSave.IsEnabled = lbxFileList.IsEnabled && isConnected;

                    lbxQueryFileList.IsEnabled = (lbxQueryFileList.Items.Count > 0);
                    btnSearch.IsEnabled = lbxQueryFileList.IsEnabled && isConnected;
                }));
        }

        private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
        {
            Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
            e.Handled = true;
        }

        private void lbxFileList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (lbxFileList.SelectedItem != null && false)
            {
                var dir = Directory.GetCurrentDirectory() + @"\Resources\DB\";
                var item = (ListBoxItem)lbxFileList.SelectedItem;
                var fileName = dir + item.Content;
                var bitmap = new BitmapImage(new Uri(fileName));
                currentImage.Source = bitmap;
            }
        }

        private void SaveImage(string fileName)
        {
            var imageName = System.IO.Path.GetFileNameWithoutExtension(fileName);
            string personName = imageName.Split('.').FirstOrDefault();

            var image = new ImageData(fileName);
            currentImage.Source = image.asBitmap;
            lblCurrentImage.Content = imageName;

            faceImage.Source = null;
            ImageData imageData;
            var imageNames = AerCloudNet_Interface.GetImageNames(personName);

            if (imageNames != null && imageNames.IndexOf(imageName) >= 0)
                MessageLogger.Default.WriteLineWithTime("[" + imageName + "] " + "Already saved"); 
            else 
                AerCloudNet_Interface.SaveImage(personName, imageName, image);

            imageData = AerCloudNet_Interface.GetImage(personName, imageName);
            if (imageData != null)
                faceImage.Source = imageData.asBitmap;
        }

        private void btnSave_Click(object sender, RoutedEventArgs e) 
        {
            if (lbxFileList.Items.Count > 0)
            {
                if (lbxFileList.SelectedItem == null)
                    lbxFileList.SelectedItem = lbxFileList.Items[0];

                if (lbxFileList.SelectedItem != null)
                {
                    var oldCursor = Cursor;
                    try
                    {
                        Cursor = Cursors.Wait;
                        var dir = Directory.GetCurrentDirectory() + @"\Resources\DB\";
                        var item = (ListBoxItem)lbxFileList.SelectedItem;
                        var fileName = dir + item.Content;
                        item.Background = Brushes.LightBlue;
                        SaveImage(fileName);
                        lbxFileList.Items.Remove(item);
                    }
                    finally
                    {
                        Cursor = oldCursor;
                    }
                }

                if (lbxFileList.Items.Count > 0)
                    lbxFileList.SelectedItem = lbxFileList.Items[0];

                UpdateControls();
            }
        }

        private void btnBrowseDatabase_Click(object sender, RoutedEventArgs e)
        {
            var win = new BrowseDatabaseWindow();
            win.Show();
        }

        private void btnSearch_Click(object sender, RoutedEventArgs e)
        {
            var item = (ListBoxItem)lbxQueryFileList.SelectedItem;
            var imageData = new ImageData((BitmapSource)imgQueryImage.Source);
            string imageName = (string)item.Content;

            SearchImage(imageName, imageData);
        }

        private void lbxQueryFileList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (lbxQueryFileList.SelectedItem != null)
            {
                var dir = Directory.GetCurrentDirectory() + @"\Resources\Query\";
                var item = (ListBoxItem)lbxQueryFileList.SelectedItem;
                var fileName = dir + item.Content;
                var bitmap = new BitmapImage(new Uri(fileName));
                imgQueryImage.Source = bitmap;
            }
        }

        private void SearchImage(string imageName, ImageData image)
        {
            if (image == null)
                return;

            imgQueryImage.Source = image.asBitmap;
            lblQueryText.Content = imageName;

            var faces = AerCloudNet_Interface.DetectFaces(imageName, image);

            if (faces != null)
            {
                int i = 1;
                foreach (var face in faces)
                {
                    var win = new BrowseSearchResults(imageName + "[" + i + "]", face.asBitmap);
                    win.Show();
                    i++;
                }
            }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            AerCloudNet_Interface.InitConnection(this);
            UpdateControls();
        }
    }
}
